package lionel.MyJMRI.MyTrain;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import java.io.File;

import javax.swing.JComponent;
import javax.swing.SwingUtilities;

import org.jdom.DataConversionException;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.ProcessingInstruction;

import jmri.DccThrottle;
import jmri.jmrit.XmlFile;
import jmri.jmrit.throttle.AddressPanel;
import jmri.jmrit.throttle.ControlPanel;
import jmri.jmrit.throttle.FunctionPanel;

import jmri.jmrit.throttle.WindowPreferences;

import lionel.MyBrowser.MyConductor;

public class MyTrain extends MyLocomotive implements PropertyChangeListener
{	
	private static final long serialVersionUID = -5499204235453587775L;

	static org.apache.log4j.Category log = org.apache.log4j.Category.getInstance(MyTrain.class.getName());

	private ControlPanel controlPanel;
	private FunctionPanel functionPanel;
	private AddressPanel addressPanel; // required for roster access
	
	private MyTrainConductor mConductor = null;
	private MyLocomotive refLoc = null;

	public MyTrain(String id) // fake constructor only for comparison
	{
		super(id);
	}

	public MyTrain(MyLocomotive myLoc) 
	{ 
		super(myLoc);
		refLoc = myLoc;
		mConductor = new MyTrainConductor( getRoster().getDccLocoAddress());
		SwingUtilities.invokeLater(new initGUI(this));
	}

	public MyConductor getConductor() {
		return mConductor;
	}
	
	public String toString()
	{
		if ((mID != null) && (mConductor!=null))
			return(mID + " / " + mConductor.toString() );
		return super.toString();
	}
	
	private void setTransparent(JComponent jcomp)
	{
		jcomp.setOpaque(false);
		Component[] comps = jcomp.getComponents();
		for (int i=0; i<comps.length; i++)
		{
			try
			{
				JComponent jcmp2 = (JComponent) comps[i];
				setTransparent( jcmp2 );
			}
			catch(Exception e)
			{
			}
		}
	}

	private class initGUI implements Runnable
	{
		MyTrain mCont;
		initGUI(MyTrain cont) { mCont = cont; }
		public void run() {
			log.debug("initGUI() start");

			controlPanel = new ControlPanel();
			controlPanel.setResizable(true);
			controlPanel.setClosable(true);
			controlPanel.setIconifiable(true);
			controlPanel.setTitle("Control Panel");
			controlPanel.pack();
			controlPanel.setEnabled(true);
			setTransparent(controlPanel);
			add(controlPanel);

			addressPanel = new AddressPanel();
			addressPanel.setRosterEntry(mRoster);

			functionPanel = new FunctionPanel();
			functionPanel.setResizable(true);
			functionPanel.setClosable(true);
			functionPanel.setIconifiable(true);
			functionPanel.setTitle("Function Panel");
			functionPanel.setSize(192, 260);
			functionPanel.setLocation(controlPanel.getWidth(), 0);
			functionPanel.pack();
			functionPanel.setEnabled(true);
			setTransparent(functionPanel);
			add(functionPanel);

			loadPrefs();
			// Force button text from Roster
			functionPanel.setAddressPanel(addressPanel); // so the function panel can get access to the roster
			mConductor.addPropertyChangeListener(functionPanel);
			mConductor.addPropertyChangeListener(controlPanel);
			mConductor.addPropertyChangeListener(mCont);
		}
	}
	
	private void checkPosition(JComponent comp)
	{ // make sure components are inside this frame bounds
		Rectangle pos = comp.getBounds();
		if ( pos.x < 0 )
			pos.x = 1;
		if ( pos.y < 0 )
			pos.y = 1;
		if (pos.x + pos.width > this.getWidth() )
			pos.width = (this.getWidth() - pos.x -1);
		if (pos.y + pos.height > this.getHeight() )
			pos.height = (this.getHeight()- pos.y -1);
		comp.setBounds(pos);		
	}
	
	private class updateGUI implements Runnable
	{
		boolean mVis;
		public updateGUI(boolean vis) { mVis = vis; }
		public void run() {
			checkPosition(controlPanel);
			checkPosition(functionPanel);
			controlPanel.setVisible(mVis);
			functionPanel.setVisible(mVis);
		}
	}

	public void setImage(File file) 
	{
		// Force renew of referred locomotive, might be changed later to specific image one loc selected
		if (refLoc!=null)
			refLoc.setImage(file);
		// But also change this one image
		loadImage(file.getPath());
	}
	
	public void propertyChange(java.beans.PropertyChangeEvent e) {
		log.debug("propertyChange: "+e.getPropertyName());
		if (e.getPropertyName().equals("Image")) {
			if ( e.getNewValue().equals("Default"))
				loadImage();
			else
				loadImage(e.getNewValue().toString());			
		} else if (e.getPropertyName().equals("Throttle")) {
			if ( e.getNewValue() != null )
			{
				DccThrottle t = (DccThrottle) e.getNewValue();
				addressPanel.notifyThrottleFound(t);
				controlPanel.notifyThrottleFound(t);
				functionPanel.notifyThrottleFound(t);
				SwingUtilities.invokeLater(new updateGUI(true));
			}
			else
			{
				if (e.getOldValue() != null)
				{
					savePrefs();
					addressPanel.notifyThrottleDisposed();
					controlPanel.notifyThrottleDisposed();
					functionPanel.notifyThrottleDisposed();
					SwingUtilities.invokeLater(new updateGUI(false));
				}
			}			
		}
	}
	
	// The code bellow is an adapted copy from the same one in JMRI for the classic throttle window.
	class MyTrainPrefs extends XmlFile {
	}
	
	protected void loadPrefs()
	{
		try {
			String imagePath = PATH_BASE + mID.trim() + "/prefs.xml";

			File file = new File(imagePath);
			MyTrainPrefs prefs = new MyTrainPrefs();
			Element root = prefs.rootFromFile(file);
			setXml(root.getChild("ThrottleFrame"));
		} catch (org.jdom.JDOMException ex) {
			log.warn("Loading trainPref exception:" + ex);
			return ;
		} catch (java.io.IOException ex) {
			log.warn("Loading trainPref exception:" + ex);
			return ;
		}
	}
	
	protected void savePrefs()
	{
		log.debug("savePrefs()");
		try {
			String imagePath = PATH_BASE + mID.trim() + "/prefs.xml";

			File file = new File(imagePath);
			MyTrainPrefs prefs = new MyTrainPrefs();
			Element root = new Element("throttle-config");
			Document doc = XmlFile.newDocument(root, XmlFile.dtdLocation+"throttle-config.dtd");
			java.util.Map m = new java.util.HashMap();
			m.put("type", "text/xsl");
			m.put("href", jmri.jmrit.XmlFile.xsltLocation+"throttle.xsl");
			ProcessingInstruction p = new ProcessingInstruction("xml-stylesheet", m);
			doc.addContent(0,p);
			Element throttleElement = getXml();
			// don't save the loco address or consist address
//			throttleElement.getChild("AddressPanel").removeChild("locoaddress");
//			throttleElement.getChild("AddressPanel").removeChild("locoaddress");
			root.setContent(throttleElement);
			prefs.writeXML(file, doc);
			
		} catch (org.jdom.JDOMException ex) {
			log.warn("Saving trainPref exception:" + ex);
			return ;
		} catch (java.io.IOException ex) {
			log.warn("Saving trainPref exception:" + ex);
			return ;
		}
	}
	
	public void setXml(Element e)
	{
		int bSize = 23;

		Element controlPanelElement = e.getChild("ControlPanel");
		controlPanel.setXml(controlPanelElement);
		if (((javax.swing.plaf.basic.BasicInternalFrameUI) controlPanel.getUI()).getNorthPane() != null)
			((javax.swing.plaf.basic.BasicInternalFrameUI) controlPanel.getUI()).getNorthPane().setPreferredSize( new Dimension(0,bSize));
		Element functionPanelElement = e.getChild("FunctionPanel");
		functionPanel.setXml(functionPanelElement);
		if (((javax.swing.plaf.basic.BasicInternalFrameUI) controlPanel.getUI()).getNorthPane() != null)
			((javax.swing.plaf.basic.BasicInternalFrameUI) functionPanel.getUI()).getNorthPane().setPreferredSize( new Dimension(0,bSize));		
		try {
			if ( e.getAttribute("controlPanelIsIconified") != null)
				controlPanel.setIcon( e.getAttribute("controlPanelIsIconified").getBooleanValue() );
			if ( e.getAttribute("functionPanelIsIconified") != null)
				functionPanel.setIcon( e.getAttribute("functionPanelIsIconified").getBooleanValue() );
		} catch (DataConversionException e1) {
			log.error("Error reading xml boolean");
			e1.printStackTrace();
		} catch (PropertyVetoException e1) {
			log.error("Can't set internal frame iconified property");
			e1.printStackTrace();
		}
	}

	public Element getXml()
	{
		Element me = new Element("ThrottleFrame");
		me.setAttribute("title", this.ID() );
		java.util.ArrayList children =  new java.util.ArrayList(1);
		children.add(controlPanel.getXml());
		children.add(functionPanel.getXml());
		me.setContent(children);
        me.setAttribute("controlPanelIsIconified", String.valueOf(controlPanel.isIcon() ));
        me.setAttribute("functionPanelIsIconified", String.valueOf(functionPanel.isIcon() ));       
		return me;
	}
}
